#!/usr/bin/perl
use FindBin;
use lib $FindBin::Bin;
use lib "$FindBin::Bin/lib";
use lib "$FindBin::Bin/../lib";
use lib "$FindBin::Bin/../plib/lib/perl5";

use strict;
use JSON;
use Getopt::Long;
use AutoExecUtils;
use CollectObjCat;
use F5Snmp;

#README
#如果新增其他品牌交换机，OID设置有问题，可能需要修改SwitchSnmp.pm, 修改开头的$BRANDS的定义，增加品牌名。
#参考：SwitchHuawei.pm
#从SwitchBase.pm继承重载before方法调整snmp oid的设置
#重载after方法，进行数据的调整或者通过其他途径补充数据

sub main {
    $| = 1;    #不对输出进行buffer，便于实时看到输出日志
    AutoExecUtils::setEnv();

    my ( $node, $defaultCommunity, $timeout );
    my $isVerbose = 0;

    GetOptions(
        'verbose=i'   => \$isVerbose,
        'node=s'      => \$node,
        'community=s' => \$defaultCommunity,
        'timeout=i'   => \$timeout
    );

    my $nodeInfo  = {};
    my $hasOptErr = 0;
    if ( not defined($node) ) {
        $node = $ENV{'AUTOEXEC_NODE'};
    }

    if ( not defined($node) or $node eq '' ) {
        print("ERROR: Option --node not defined.\n");
        $hasOptErr = 1;
    }
    else {
        $nodeInfo = from_json($node);
    }

    if ( not defined($timeout) ) {
        $timeout = 10;
    }

    my $hostname     = $nodeInfo->{host};
    my $community    = $nodeInfo->{password};
    my $protocol     = $nodeInfo->{protocol};
    my $protocolPort = $nodeInfo->{protocolPort};

    #version (i.e. 'snmpv1', 'snmpv2c', or 'snmpv3')
    if ( not defined($protocol) or $protocol eq '' or $protocol eq 'snmp' ) {
        $protocol = 'snmpv2c';
    }

    if ( not defined($community) or $community eq '' ) {

        #如果执行节点给出的协议不是snmp或者没有给出密码，则使用默认密码选项给出的团体字
        $community = $defaultCommunity;
    }
    if ( not defined($community) or $community eq '' ) {
        $community = 'public';
    }

    my $usmData  = {};
    my $authData = $nodeInfo->{authData};
    if ( defined($authData) ) {

        #snmpv3
        $usmData->{version}      = 'snmpv3';
        $usmData->{username}     = $authData->{username};
        $usmData->{authpassword} = $authData->{authPassword};
        $usmData->{authprotocol} = $authData->{authProtocol};
        $usmData->{privpassword} = $authData->{privPassword};
        $usmData->{privprotocol} = $authData->{privProtocol};

        if ( not defined( $usmData->{username} ) ) {
            $usmData->{username} = $nodeInfo->{username};
        }
        if ( not defined( $usmData->{authpassword} ) ) {
            $usmData->{authpassword} = $community;
        }
    }
    else {
        #snmpv2
        $usmData->{version}   = $protocol;
        $usmData->{community} = $community;
    }

    my $collector = F5Snmp->new( hostname => $node->{host}, port => $protocolPort, timeout => $timeout, %$usmData );
    my $data      = $collector->collect();
    my $objCat    = CollectObjCat->get('LOADBALANCER');
    $data->{_OBJ_CATEGORY} = $objCat;
    $data->{_OBJ_TYPE}     = 'F5';
    $data->{PK}            = ['MGMT_IP'];
    $data->{RESOURCE_ID}   = $node->{resourceId};
    $data->{MGMT_IP}       = $node->{host};

    #my $upTime = int( $data->{UPTIME} / 86400 + 0.5 ) / 100;
    my $upTime = int( $data->{UPTIME} );
    $data->{UPTIME} = $upTime;

    my @outData        = ($data);
    my $virtualServers = $data->{VIRTUAL_SERVERS};
    foreach my $vsInfo (@$virtualServers) {
        my $clusterInfo = {
            'PK'               => CollectObjCat->getPK($objCat),
            '_OBJ_CATEGORY'    => CollectObjCat->get('CLUSTER'),
            '_OBJ_TYPE'        => 'LoadBalancer-VS',
            'CLUSTER_MODE'     => 'LoadBalance',
            'CLUSTER_SOFTWARE' => 'F5',
            'CLUSTER_VERSION'  => $data->{VERSION},
            'HOST_ON'          => {
                '_OBJ_CATEGORY' => 'LOADBALANCER',
                '_OBJ_TYPE'     => 'F5',
                'DEV_NAME'      => $data->{DEV_NAME},
                'SN'            => $data->{SN},
                'MGMT_IP'       => $node->{host},
                'RESOURCE_ID'   => $node->{resourceId}
            }
        };
        my $bind = $vsInfo->{IP} . ':' . $vsInfo->{PORT};
        $clusterInfo->{NAME}        = $vsInfo->{NAME};
        $clusterInfo->{VIP}         = $vsInfo->{IP};
        $clusterInfo->{PRIMARY_IP}  = $vsInfo->{IP};
        $clusterInfo->{PORT}        = $vsInfo->{PORT};
        $clusterInfo->{BIND}        = [$bind];
        $clusterInfo->{UNIQUE_NAME} = "F5:$bind";

        $vsInfo->{_OBJ_CATEGORY} = 'LOADBALANCER';
        $vsInfo->{_OBJ_TYPE}     = 'LOADBALANCER-VS';

        my @memberPeer = ();
        my $members    = $vsInfo->{POOL}->{MEMBERS};
        foreach my $memberInfo (@$members) {
            $memberInfo->{_OBJ_CATEGORY} = 'LOADBALANCER';
            $memberInfo->{_OBJ_TYPE}     = 'LOADBALANCER-MEMBER';
            push( @memberPeer, $memberInfo->{IP} . ':' . $memberInfo->{PORT} );
        }

        my $pool = $vsInfo->{POOL};
        if (%$pool) {
            $pool->{_OBJ_CATEGORY} = 'LOADBALANCER';
            $pool->{_OBJ_TYPE}     = 'LOADBALANCER-POOL';
            $vsInfo->{POOL}        = [$pool];
        }
        else {
            $vsInfo->{POOL} = [];
        }

        $clusterInfo->{MEMBER_PEER} = \@memberPeer;
        push( @outData, $clusterInfo );
    }
    print("INFO: Information collected.\n");
    my $out = {};
    $out->{DATA} = \@outData;
    AutoExecUtils::saveOutput($out);
    if ( $isVerbose == 1 ) {
        print("==================\n");
        print( to_json( $data, { pretty => 1 } ) );
        print("==================\n");
    }

    return 0;
}

exit main();
